﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Fadd.Messaging;
using Fadd.Net;
using Xunit;

namespace Fadd.Test.Messaging
{/*
    public class ConnectedDistributors
    {
        private readonly RemoteMessagingChannel _channelSlave1;
        private readonly RemoteMessagingChannel _channelSlave2;

        private readonly MessageBroker _master =
            new MessageBroker(new BrokerConfiguration {NoConsumersForMessage = ExceptionPolicy.Ignore});

        private readonly MessageBroker _slave1 = new MessageBroker();
        private readonly MessageBroker _slave2 = new MessageBroker();
        private RemoteMessagingChannel _serverSlave1, _serverSlave2;

        public ConnectedDistributors()
        {
            var ep = new IPEndPoint(IPAddress.Loopback, 9948);
            var server = new SimpleServer(ep,
                                          s =>
                                              {
                                                  if (_serverSlave1 == null)
                                                      _serverSlave1 = new RemoteMessagingChannel(s);
                                                  else
                                                      _serverSlave2 = new RemoteMessagingChannel(s);
                                              });
            server.Start(5);


            _channelSlave1 = new RemoteMessagingChannel(ep);
            _channelSlave2 = new RemoteMessagingChannel(ep);
            Thread.Sleep(500);

            _channelSlave1.StartAsPublisher(_slave1);
            _channelSlave2.StartAsPublisher(_slave2);
            _serverSlave1.StartAsListener(_master);
            _serverSlave2.StartAsListener(_master);
        }

        [Fact]
        public void TestDistribution()
        {
            bool slave1 = false, slave2 = false;
            _slave1.Published += (s, e) => slave1 = true;
            _slave2.Published += (s, e) => slave2 = true;

            _master.Publish(new TestMessage1());
            Thread.Sleep(500);

            Assert.True(slave1);
            Assert.True(slave2);
        }

        [Fact]
        public void TestReconnect()
        {
        }

        #region Nested type: SuperServer

        public class SuperServer
        {
            private List<ClientContext> _clients = new List<ClientContext>();
            private SimpleServer _server;
            private Pool<byte[]> _bufferPool;

            public SuperServer()
            {
                // Create a buffer pool to be able to reuse buffers
                // since your clients will most likely connect and disconnect
                // often.
                //
                // The pool takes a anonymous function which should return a new buffer.
                //
                // Pool source:
                // http://fadd.codeplex.com/SourceControl/changeset/view/58858#1054902
                _bufferPool = new Pool<byte[]>(() => new byte[65535]);
            }

            public void SendToAll(byte[] info)
            {
                lock (_clients)
                {
                    foreach (var client in _clients)
                        client.Socket.BeginSend(info, 0, info.Length, SocketFlags.None, null, null);
                }
            }

            public void Start(IPEndPoint listenAddress)
            {
                // You can download my simple server from here:
                // http://fadd.codeplex.com/SourceControl/changeset/view/58857#1054893
                _server = new SimpleServer(listenAddress, OnAcceptedSocket);

                // Allow five connections to be queued (to be accepted)
                _server.Start(5); 
            }

            private void OnAcceptedSocket(Socket socket)
            {
                var context = new ClientContext();
                context.Inbuffer = _bufferPool.Dequeue();
                context.Socket = socket;

                lock (_clients)
                    _clients.Add(context);

                // this method will eat very few resources and
                // there should be no problem having 5000 waiting sockets.
                context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
                                            context);
            }

            private void OnRead(IAsyncResult ar)
            {
                var context = (ClientContext) ar.AsyncState;
                try
                {
                    var bytesRead = context.Socket.EndReceive(ar);
                    if (bytesRead == 0)
                    {
                        HandleClientDisconnection(context);
                        return;
                    }

                    // process context.Inbuffer here.
                }
                catch (Exception err)
                {
                    //log exception here.
                    HandleClientDisconnection(context);
                    return;
                }

                // use a new try/catch to make sure that we start
                // read again event if processing of last bytes failed.
                try
                {
                    context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
                                                context);
                }
                catch (Exception err)
                {
                    //log exception here.
                    HandleClientDisconnection(context);
                }
            }

            private void HandleClientDisconnection(ClientContext context)
            {
                _bufferPool.Enqueue(context.Inbuffer);
                try
                {
                    context.Socket.Close();
                    lock (_clients)
                        _clients.Remove(context);
                }
                catch(Exception err)
                {
                    //log exception
                }
            }


            // One of your modems
            // add your own state info.
            private class ClientContext
            {
                public byte[] Inbuffer;
                public Socket Socket;
            }

        }

        #endregion
    }
*/}
